home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / flying-6.11 / xmover.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-30  |  25.9 KB  |  1,046 lines

  1. //
  2. // XMover: Modul zur Optimierten Ball-Darstellung unter XWindows
  3. // - flackerfreies Bewegen der BΣlle durch Hilfspixmaps
  4. // - Beleuchtungseffekt durch Raytracing-Bitmaps
  5. // - Darstellung halber Kugeln durch vorberechnete Pixmaps
  6. //
  7.  
  8. #ifndef _vec3_h
  9. #    include "vec3.h"
  10. #endif
  11.  
  12. #define    LEFT_RIGHT_OPT
  13. #define    USE_STUFFER
  14.  
  15. /*----------------------------------------------------------------------------*/
  16.  
  17. //
  18. // Klasse zur Komprimierung der RingState-Felder
  19. //
  20. class Stuffer {
  21.     public:
  22.         Stuffer() : ws(0), wl(sizeof(unsigned long))            {}
  23.  
  24.         void Init( int ws_in, int wl_in ) {
  25.                 ws = ws_in;
  26.                 if (wl!=wl_in) {
  27.                     printf( "ERROR: Stuffer only for unsigned longs !\n" );
  28.                     exit(0);
  29.                 }
  30.         }
  31.         void Shrink( void *addr, int len );
  32.         void Expand( void *addr, int len );
  33.         int  SSize( int len )
  34. #ifdef USE_STUFFER
  35.         {        return ((len*ws+7)/8);    }
  36. #else
  37.         {        return ((len*wl+7)/8);    }
  38. #endif
  39.         int  LSize( int len )
  40.         {        return ((len*wl+7)/8);    }
  41.  
  42.     private:
  43.         int    ws;    // Bits klein
  44.         const int    wl;    // Bits gross
  45.         static mtab[9];
  46. };
  47.  
  48. int Stuffer::mtab[9] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
  49.  
  50. #ifdef USE_STUFFER
  51. void Stuffer::Shrink( void *addr, int len ) {
  52. unsigned long    *r_p;
  53. unsigned long    r_val;
  54. int    r_len;
  55. unsigned char    *w_p;
  56. unsigned char    w_val;
  57. int    w_space;
  58.  
  59.     r_p     = (unsigned long*)addr;
  60.     w_p     = (unsigned char*)addr;
  61.     w_space = 8;
  62.     w_val   = 0;
  63.     while( len-- ) {
  64.         r_val = *r_p++;
  65.         r_len = ws;
  66.  
  67.         while (r_len>=w_space) {
  68.             w_val  |= ((unsigned char)r_val)&mtab[w_space];
  69.             *w_p++  = w_val;
  70.             w_val   = 0;
  71.             r_val >>= w_space;
  72.             r_len  -= w_space;
  73.             w_space = 8;
  74.         }
  75.  
  76.         if (r_len) {
  77.             w_val   |= (((unsigned char)r_val)&mtab[w_space])<<(w_space-r_len);
  78.             w_space -= r_len;
  79.         }
  80.     }
  81.     *w_p++ = w_val;
  82. }
  83.  
  84. void Stuffer::Expand( void *addr, int len ) {
  85. unsigned long    *w_p;                    // Schreibzeiger - expandiertes Ende
  86. unsigned long    w_val;
  87. int    w_space;                            // fehlende Bits zum Gesamtwort
  88. unsigned char    *r_p;                    // Lesezeiger - komprimiertes Ende
  89. unsigned char    r_val;                // gueltige Bits
  90. int    r_len;                            // Zahl gueltige Bits an Lesezeigerposition
  91.  
  92.     r_p     = (unsigned char*)addr + len*ws/8;        // Adresse des letzten Byte
  93.     r_len   = (len*ws)%8;            // gⁿltige Bits im letzen Byte
  94.     if (r_len)    r_val = *r_p;        // letzte Bits holen
  95.     else {        r_val = *--r_p;
  96.                     r_len = 8;
  97.     }
  98.     w_p     = (unsigned long*)addr + len;
  99.  
  100.     while( len-- ) {
  101.         w_space = ws;
  102.         w_val   =  0;
  103.         while( r_len<=w_space ) {
  104.             w_val <<= r_len;
  105.             w_val  |= r_val>>(8-r_len);
  106.             w_space-= r_len;
  107.             r_val   = *--r_p;            // ABR: liest 1 Byte ueber die Untergrenze
  108.             r_len   = 8;
  109.         }
  110.         if (w_space) {
  111.             w_val   <<= w_space;
  112.             w_val    |= r_val&mtab[w_space];
  113.             r_len    -= w_space;
  114.         }
  115.         *--w_p  = w_val;
  116.     }
  117. }
  118.  
  119. #else
  120. void Stuffer::Shrink( void *, int ) {}
  121. void Stuffer::Expand( void *, int ) {}
  122. #endif
  123.  
  124. /*----------------------------------------------------------------------------*/
  125.  
  126. class Bitmap {
  127. public:
  128.     void Clear()    {    memset( bits, 0, bytes_per_line*height ); }
  129.  
  130.     void Init( int w, int h, char *bmap ) {
  131.         width                = w;
  132.         bytes_per_line = (width+7)/8;
  133.         height             = h;
  134.         bits                 = bmap;
  135.     }
  136.     Bitmap( int w, int h, char *bmap )    { Init(w,h,bmap); }
  137.     Bitmap()                                        {}
  138.  
  139.     int GetPixel( int x, int y ) {
  140.         if ((x<0)||(x>=width)||(y<0)||(y>=height))        return 0;
  141.         else {
  142.             unsigned char mask = 1<<(x&7);
  143.             return (bits[bytes_per_line*y+(x>>3)]&mask)?1:0;
  144.         }
  145.     }
  146.     void SetPixel( int x, int y ) {
  147.         unsigned char mask = 1<<(x&7);
  148.         bits[bytes_per_line*y+(x>>3)] |= mask;
  149.     }
  150.     void ClrPixel( int x, int y ) {
  151.         unsigned char mask = 1<<(x&7);
  152.         bits[bytes_per_line*y+(x>>3)] &= ~mask;
  153.     }
  154.  
  155.  
  156.     Pixmap Create() {
  157.         return XCreatePixmapFromBitmapData(dpy,win,bits,width,height,1,0,1 );
  158.     }
  159.     void Print();
  160.  
  161.     int    width;
  162.     int    height;
  163. protected:
  164.     int    bytes_per_line;
  165.     char *bits;
  166. };
  167.  
  168. class LocBitmap : public Bitmap {
  169. public:
  170.     void Init( int w, int h ) {
  171.         Bitmap::Init(w,h,0);
  172.         bits                 = new char[bytes_per_line*height];
  173.         Clear();
  174.     }
  175.     void Init( int w, int h,  FILE *fp ) {
  176.         Bitmap::Init(w,h,0);
  177.         bits                 = new char[bytes_per_line*height];
  178.         fread(bits,sizeof(char),bytes_per_line*height,fp);
  179.     }
  180.     void Write( FILE *fp ) {
  181.         fwrite(bits,sizeof(char),bytes_per_line*height,fp);
  182.     }
  183.     LocBitmap( int w, int h )        { Init(w,h); }
  184.  
  185.     LocBitmap()        {}
  186.     ~LocBitmap()        { delete bits; }
  187.  
  188.     // change for a sun sparc-station runing 4.1.3 that thinks:
  189.     // xmover.c:463: no non-hidden member function 'LocBitmap::create' defined
  190.     Pixmap Create() { return Bitmap::Create(); }
  191. };
  192.  
  193.  
  194. void Bitmap::Print() {
  195.     for(int y=0;y<height;y++) {
  196.         for(int x=0;x<width;x++)    printf( "%d", GetPixel(x,y) );
  197.         printf( "\n" );
  198.     }
  199. }
  200.  
  201. /*----------------------------------------------------------------------------*/
  202.  
  203. #ifdef STATISTICS
  204. unsigned long    BallMover::moves = 0l;
  205. #endif
  206.  
  207. BallMover::BallMover( const Real &r_in ) {
  208.     r = (int)(r_in*w2n);    // Radius als Member festhalten
  209.     d = 2*r;                    // Bem: Durchmesser immer gerade
  210.  
  211.     bpix = help = 0;
  212. }
  213.  
  214.  
  215. BallMover::~BallMover() {
  216.     if (help)    XFreePixmap( dpy, help );
  217.     if (bpix)    XFreePixmap( dpy, bpix );
  218. }
  219.  
  220.  
  221. void BallMover::Init() {
  222. LocBitmap    *bit;            // Kugelbitmap
  223. int        x,y;
  224. double    dr=r-0.5;        // tatsΣchlicher (Welt-)Radius
  225.  
  226.     bit = new LocBitmap( d, d );
  227.     max_rad  = r-0.25+EPS;
  228.     max_rad2 = max_rad * max_rad;
  229.     for (y=0;y<d;y++) {
  230.         for (x=0;x<d;x++) {
  231.             double dx = x-dr;                                // X-Abstand zur Kreismitte
  232.             double dy = y-dr;                                // Y-Abstand zur Kreismitte
  233.             double dist2 = dx*dx + dy*dy;
  234.             if (dist2<max_rad2) {
  235.                 bit->SetPixel(x,y);
  236.             }
  237.         }
  238.     }
  239.  
  240.     bpix = bit->Create();
  241.  
  242.     d_help    = 2*d-1;
  243.     help        = XCreatePixmap(dpy,win,d_help,d_help,DefaultDepth(dpy,0));
  244.  
  245.     delete bit;
  246. }
  247.  
  248. void BallMover::DrawBallAt( int x, int y, int col_x )
  249. {
  250. #ifndef NODRAW
  251.     XFillRectangle(dpy,help,gc_bclear,0,0,d,d);
  252.     XCopyPlane(dpy,bpix,help,gc_ball[col_x],0,0,d,d,0,0,1);
  253.     Pixmap    shadow = GetShadowMap(x,y);
  254.     if (shadow)    XCopyPlane(dpy,shadow,help,gc_lay2,0,0,d,d,0,0,1);
  255.     XCopyArea(dpy,help,win,gc_bxor,0,0,d,d,x-r, y-r );
  256. #endif
  257. }
  258.  
  259.  
  260. void BallMover::MoveBallOnScreen( int oldx, int oldy, int newx, int newy, int col_x ) {
  261.  
  262. int    dx = newx-oldx;
  263. int    dy = newy-oldy;
  264. int absx = (dx>0)?dx:-dx;
  265. int absy = (dy>0)?dy:-dy;
  266.  
  267. #ifndef NODRAW
  268.     if ( (absx<d_help-d) && (absy<d_help-d) ) {
  269.         Pixmap    shadow;
  270.  
  271.         int    width = d+absx;        // tatsΣchlicher Ausschnittgr÷▀e der Pixmap
  272.         int    height= d+absy;
  273.         int    ox = (dx>0)?0:absx;    // relativer Abstand alte Position
  274.         int    oy = (dy>0)?0:absy;
  275.         int    nx = (dx>0)?absx:0;    // relativer Abstand neue Position
  276.         int    ny = (dy>0)?absy:0;
  277.  
  278.         XFillRectangle(dpy,help,gc_bclear,0,0,width,height);
  279.  
  280.         XCopyPlane(dpy,bpix,help,gc_ball[col_x],0,0,d,d,ox,oy,1);
  281.         shadow = GetShadowMap(oldx,oldy);
  282.         if (shadow)    XCopyPlane(dpy,shadow,help,gc_lay2,0,0,d,d,ox,oy,1);
  283.  
  284.         XCopyPlane(dpy,bpix,help,gc_ball[col_x],0,0,d,d,nx,ny,1);
  285.         shadow = GetShadowMap(newx,newy);
  286.         if (shadow)    XCopyPlane(dpy,shadow,help,gc_lay2,0,0,d,d,nx,ny,1);
  287.  
  288.         XCopyArea(dpy,help,win,gc_bxor,0,0,width,height,oldx-ox-r, oldy-oy-r );
  289.     }
  290.     else {
  291.         DrawBallAt(oldx,oldy,col_x);
  292.         DrawBallAt(newx,newy,col_x);
  293.     }
  294. #endif
  295.  
  296. #ifdef STATISTICS
  297.     moves++;
  298. #endif
  299. }
  300.  
  301. Pixmap BallMover::GetShadowMap( int /*x*/, int /*y*/ )        { return 0; }
  302.  
  303. // -------------------------------------------------------------------------
  304.  
  305. DiscMover::DiscMover( const Real &r ) :
  306.     BallMover( r )
  307. {
  308.     lpix = 0;
  309. }
  310.  
  311. DiscMover::~DiscMover()
  312. {
  313.     if (lpix)    XFreePixmap(dpy,lpix);
  314. }
  315.  
  316. void DiscMover::Init() {
  317. LocBitmap    *lbit;        // Kreisbitmap
  318. int        x,y;
  319. double    dr=r-0.5;        // tatsΣchlicher (Welt-)Radius
  320.  
  321.     BallMover::Init();
  322.  
  323.     lbit    = new LocBitmap( d, d );
  324. double    shade_rad    = 1.2;            // Pixelbreite in WS-umgerechnet
  325. double    inner1        = r*1/4;
  326. double    inner2        = r*2/4;
  327.  
  328.     for (y=0;y<d;y++) {
  329.         for (x=0;x<d;x++) {
  330.             double dx = x-dr;                                // X-Abstand zur Kreismitte
  331.             double dy = y-dr;                                // Y-Abstand zur Kreismitte
  332.             double dist = sqrt(dx*dx + dy*dy);
  333.             if (dist<max_rad) {
  334.                 if (  (dist>max_rad-shade_rad)
  335.                     || (dist>inner1-shade_rad)&&(dist<inner1)
  336.                     || (dist>inner2-shade_rad)&&(dist<inner2) ) {
  337.                     lbit->SetPixel(x,y);
  338.                 }
  339.             }
  340.         }
  341.     }
  342.  
  343.     lpix = lbit->Create();
  344.     delete lbit;
  345. }
  346.  
  347. Pixmap DiscMover::GetShadowMap( int /*x*/, int /*y*/ )        { return lpix; }
  348.  
  349. // -------------------------------------------------------------------------
  350.  
  351. ShadedBallMover::ShadedBallMover( const Real &r ) :
  352.     BallMover( r )
  353. {
  354.     lpix=0;
  355. }
  356.  
  357. ShadedBallMover::~ShadedBallMover()
  358. {
  359.     if (lpix) {
  360.         for (int i=0;i<lpixs_all;i++) {
  361.             XFreePixmap( dpy, lpix[i] );
  362.         }
  363.         delete [] lpix;
  364.         lpix = 0;
  365.     }
  366. }
  367.  
  368. #if (0)
  369. const    double circ_x    =  -50.0;
  370. const    double circ_y    =  -50.0;
  371. const    double circ_r1 =  150.0;
  372. const    double circ_r2 =  300.0;
  373. #endif
  374.  
  375.  
  376. void ShadedBallMover::Init() {
  377. int            x,y,i;
  378.  
  379. LocBitmap    *lbit;    // Feld der Hilfbitmaps
  380.  
  381. double    dr=r-0.5;        // tatsΣchlicher (Welt-)Radius
  382.  
  383. int        ncircs;            // number of lamps
  384. double    circ_z;            // hight of lamps
  385. struct lightdata {
  386.     double    x,y;            // position of lamps
  387.     double    r1, r2;        // size (inner/outer) of lamps
  388. }            circ[3];
  389.  
  390.     BallMover::Init();
  391.  
  392.     if (light_flag) {
  393.         lpixs_x = 24;                                 // Zahl der Bitmaps in X-Richtung
  394.         lpixs_y = 12;                                    // Zahl der Bitmaps in Y-Richtung
  395.     }
  396.     else {
  397.         lpixs_x = 0;
  398.         lpixs_y = 0;
  399.     }
  400.     lpixs_all = lpixs_x * lpixs_y;            // Gesamtzahl
  401.     distx = max_x / lpixs_x;                    // Weltkoordinatenraster X
  402.     disty = max_y / lpixs_y;                    // Weltkoordinatenraster Y
  403.     lbit = new LocBitmap[lpixs_all];            // Anlegen der Bitmaps
  404.     for (i=0;i<lpixs_all;i++)     lbit[i].Init(d,d);
  405.  
  406.     if (light_flag<=1) {
  407.         ncircs = 1;                                // single light, far far away
  408.         circ_z = 2000.0;
  409.         circ[0].x= -50.0; circ[0].y= -50.0; circ[0].r1= 150.0; circ[0].r2 = 300.0;
  410.     }
  411.     else {
  412.         ncircs = 3;
  413.         circ_z = MaxX() * 2.0 / 3.0;        // einfach 'mal so angenommen
  414.         for (int l=0;l<ncircs;l++) {
  415.             circ[l].x  = MaxX() * (double)(l+1) / 4.0;
  416.             circ[l].y  = MaxY() /  2.0;
  417.             circ[l].r1 = MaxX() / 16.0;
  418.             circ[l].r2 = MaxX() /  8.0;
  419.         }
  420.     }
  421.  
  422.  
  423.     DBG1( UnixTrace, "Starting image processing with ball size %d pixel:\n", d );
  424.     DBG1( UnixTrace, "BitmapData: >%ld bytes\n", (d+7)/8*d*lpixs_all );
  425.  
  426.     for (y=0;y<d;y++) {                            // Fⁿr alle Punkte der Bitmaps
  427.         for (x=0;x<d;x++) {
  428.             double dx = x-dr;                                // X-Abstand zur Kreismitte
  429.             double dy = y-dr;                                // Y-Abstand zur Kreismitte
  430.             double dist2 = dx*dx + dy*dy;
  431.             if (dist2<max_rad2) {
  432.  
  433.                 double dz = dr*dr-dist2;                // quadratischer Z-Abstand
  434.                 if (dz>=0) {
  435.                     double f = circ_z/sqrt(dz);        // Multiplikator zur Decke
  436.                     dx *= f;                                    //    XPos an Decke
  437.                     dy *= f;                                    // YPos an Decke
  438.  
  439.                     for (int px=0;px<lpixs_x;px++) {    // fⁿr alle Bitmaps
  440.                         for (int py=0;py<lpixs_y;py++) {
  441.                             int    lflag=0;        // 0-dark, 1-medium, 2-light
  442.                             for (int l=0;l<ncircs;l++) {
  443.                             // Weltposition relativ zu Kreislicht
  444.                                 double wx = (px*distx+(distx>>1)+dx)/w2n-circ[l].x;
  445.                                 double wy = (py*disty+(disty>>1)+dy)/w2n-circ[l].y;
  446.                                 double d = wx*wx+wy*wy;
  447.                                 if (d<circ[l].r2*circ[l].r2) {
  448.                                     if (d<circ[l].r1*circ[l].r1) {
  449.                                         // inner circle
  450.                                             lflag=2; break;
  451.                                     }
  452.                                     else    lflag=1;
  453.                                 }
  454.                             }
  455.                             if ( (lflag==2) || (lflag&&((x^y)&1)) ) {
  456.                                 lbit[px+py*lpixs_x].SetPixel(x,y);
  457.                             }
  458.                         }
  459.                     }
  460.                 }
  461.             }
  462.         }
  463.     }
  464.  
  465.     lpix = new Pixmap[lpixs_all];
  466.     for (i=0;i<lpixs_all;i++) {
  467.         lpix[i] = lbit[i].Create();
  468.     }
  469.     delete [] lbit;
  470. }
  471.  
  472.  
  473. Pixmap ShadedBallMover::GetShadowMap( int x, int y ) {
  474. int    xp = x/distx;
  475.     if (xp<0)            xp=0;
  476.     if (xp>=lpixs_x)    xp=lpixs_x-1;
  477. int    yp = y/disty;
  478.     if (yp<0)            yp=0;
  479.     if (yp>=lpixs_y)    yp=lpixs_y-1;
  480.  
  481.     return lpix[xp+yp*lpixs_x];
  482. }
  483.  
  484.  
  485. void ShadedBallMover::CreateLightWindow() {
  486. Window    help;
  487. const int o=2;
  488.  
  489.     help=CreateWindow( "Beleuchtung", lpixs_x*(d+o)+1 , lpixs_y*(d+o)+1 );
  490.     for (int px=0;px<lpixs_x;px++) {
  491.         for (int py=0;py<lpixs_y;py++) {
  492.             XCopyPlane(dpy,bpix,help,gc_ball[2],0,0,d,d,o/2+px*(d+o),o/2+py*(d+o),1);
  493.             XCopyPlane(dpy,lpix[px+py*lpixs_x],help,gc_lay2,0,0,d,d,o/2+px*(d+o),o/2+py*(d+o),1);
  494.  
  495.         }
  496.     }
  497. }
  498.  
  499. // -------------------------------------------------------------------------
  500.  
  501. const int HalfBallMover::o=4;
  502.  
  503. HalfBallMover::HalfBallMover( const Real &r, int mode_in ) :
  504.     ShadedBallMover( r )
  505. {
  506.     rpix    = 0;        // Ring-Pixmap-Feld
  507.     nbpix = 0;        // negative Pixmap zum Debuggen
  508.     tw        = 0;
  509.     mode    = mode_in;
  510.  
  511.     right = left = up = down = 0;
  512. }
  513.  
  514. HalfBallMover::~HalfBallMover()
  515. {
  516.     if (rpix) {
  517.         for (int i=0;i<rpixs_all;i++) {
  518.             XFreePixmap( dpy, rpix[i] );
  519.         }
  520.         delete [] rpix;
  521.         rpix = 0;
  522.     }
  523.     if (nbpix)        XFreePixmap( dpy, nbpix );
  524.  
  525.     if (right)        delete [] right;
  526.     if (left)        delete [] left;
  527.     if (up)            delete [] up;
  528.     if (down)        delete [] down;
  529. }
  530.  
  531. void HalfBallMover::Init() {
  532. int            x,y,i,l,b;
  533.  
  534. LocBitmap    *rbit;    // Feld der Ring-Bitmaps
  535. Vec3            *pv;        // Vec2 zum Pol der Kugel der entsprechenden Bitmap
  536.  
  537.     ShadedBallMover::Init();
  538.  
  539. //
  540. // Zahl der Pixmap's, Gr÷▀e der Felder bestimmen
  541. //
  542.     sym = (mode>1)?2.0:1.0;
  543.     //sym = 1.0;
  544.  
  545.     if (mode) {
  546.         rpixs_l   = (int)(3.14*d/sym);   // Zahl der Bitmaps in LΣngen-Richtung
  547.         rpixs_b   = (int)(3.14*d/2.0);    // Zahl der Bitmaps in Breiten-Richtung
  548.         mult    = 6;                                // Internes Raster
  549.     }
  550.     else {
  551.         rpixs_l = rpixs_b = 1;
  552.         mult = 1;
  553.     }
  554.     mult2 = mult/2;
  555.     rpixs_all = rpixs_l * rpixs_b;        // Gesamtzahl
  556.  
  557.     vecs_l    = rpixs_l * mult;            // Hilfsraster feiner als Bitmap-Raster
  558.     vecs_b    = rpixs_b * mult;
  559.  
  560.     vecs_all  = vecs_l * vecs_b;            // Gesamtgr÷▀e des Rasters
  561.     for (i=0;i<sizeof(RingState);i++)    vecs_all/=256;
  562.     if (vecs_all>0) {
  563.         printf( "too many RingStates (%d) -> switch type to unsigned long\n",
  564.                     vecs_l * vecs_b );
  565.         exit(0);
  566.     }
  567.     vecs_all  = vecs_l * vecs_b;            // Gesamtgr÷▀e des Rasters
  568.  
  569. char    fname[80];
  570.     sprintf(fname,"%s/fly%d-%d.dta",DATA_DIRECTORY,mode,d);
  571. FILE    *fp;
  572.  
  573. #ifdef DEBUG
  574.     fp = (debug&ForceCalc)?0:fopen( fname, "r" );
  575. #else
  576.     fp = fopen( fname, "r" );
  577. #endif
  578.  
  579.     rbit = new LocBitmap[rpixs_all];        // Anlegen der Bitmaps
  580.     for (l=0;l<rpixs_l;l++) {                // fⁿr alle Bitmaps
  581.         for (b=0;b<rpixs_b;b++) {
  582.             if (!fp)    rbit[PixIndex(l,b)].Init(d,d);
  583.             else        rbit[PixIndex(l,b)].Init(d,d,fp);
  584.         }
  585.     }
  586.  
  587.     pv   = new Vec3[d*d];
  588.     for (y=0;y<d;y++) {
  589.         for (x=0;x<d;x++) {
  590.             double dx = x-r+0.5;                                // X-Abstand zur Kreismitte
  591.             double dy = y-r+0.5;                                // Y-Abstand zur Kreismitte
  592.             double dist2 = dx*dx + dy*dy;                    // Dist. zur sichtbaren Mitte
  593.             if (dist2<max_rad2) {
  594.         //        double dzr = sqrt(dr*dr-dy*dy);        // Kugel-Radius auf H÷he z
  595.         //        double dz  = sqrt(dzr*dzr-dx*dx);    // fehlende Tiefenkoordinate
  596.                 double dz  = sqrt(r*r-dist2);
  597.                 pv[x+y*d] = Vec3( dx, dz, dy );
  598.             }
  599.             else {
  600.                 pv[x+y*d] = Vec3( 0.0, 0.0, 0.0 );
  601.             }
  602.         }
  603.     }
  604.  
  605. #ifdef DEBUG
  606. double    start_time = GetCurrentTime();
  607. #endif
  608.  
  609.     if (!fp) {
  610.         DBG3( UnixTrace, "Rings need %dx%d=%d Bitmaps\n",rpixs_l,rpixs_b,rpixs_all);
  611.         DBG1( UnixTrace, "BitmapData:   >%7ld Bytes\n", (d+7)/8*d*rpixs_all );
  612.         DBG1( UnixTrace, "+ temporary:  >%7ld Bytes\n",
  613.                      d*d*(sizeof(Vec3)+sizeof(Bitmap)+(d*(d+7)/8) ) );
  614.  
  615. //
  616. // Bitmaps ausrechen
  617. //
  618.         printf( "image processing: 00%%" ); fflush(stdout);
  619.  
  620.         for (l=0;l<rpixs_l;l++) {    // fⁿr alle Bitmaps
  621.             printf( "\b\b\b%02d%%", (int)100*l/rpixs_l ); fflush(stdout);
  622.             for (b=0;b<rpixs_b;b++) {
  623.                 Vec3    v = Vec3( lToDeg(l*mult+mult2), bToDeg(b*mult+mult2) )*Real(r);
  624.                 switch(mode) {
  625.                 case 1:    for (y=0;y<d;y++) {        // Volle Kugeln
  626.                                 for (x=0;x<d;x++) {
  627.                                     if (!pv[x+y*d].IsZero()) {
  628.                                         Real    ang = v.AngleRadTo( pv[x+y*d] );
  629.                                         if (ang>0.35)    rbit[PixIndex(l,b)].SetPixel(x,y);
  630.                                     }
  631.                                 }
  632.                             }
  633.                             break;
  634.                 case 2:    for (y=0;y<d;y++) {        // Halbe Kugeln
  635.                                 for (x=0;x<d;x++) {
  636.                                     if (!pv[x+y*d].IsZero()) {
  637.                                         Real    ang = v.AngleRadTo( pv[x+y*d] );
  638.                                         if (ang>1.0708 && ang<2.0708)
  639.                                             rbit[PixIndex(l,b)].SetPixel(x,y);
  640.                                     }
  641.                                 }
  642.                             }
  643.                             break;
  644.                 case 3:    for (y=0;y<d;y++) {        // Volle Kugeln 2
  645.                                 for (x=0;x<d;x++) {
  646.                                     if (!pv[x+y*d].IsZero()) {
  647.                                         Real    ang = v.AngleRadTo( pv[x+y*d] );
  648.                                         if (ang>0.35)    rbit[PixIndex(l,b)].SetPixel(x,y);
  649.                                     }
  650.                                 }
  651.                             }
  652.                             break;
  653.                 case 4:    for (y=0;y<d;y++) {        // Halbe Kugeln 2
  654.                                 for (x=0;x<d;x++) {
  655.                                     if (!pv[x+y*d].IsZero()) {
  656.                                         Real    ang = v.AngleRadTo( pv[x+y*d] );
  657.                                         if ((ang>0.35&&ang<1.27)||(ang>1.87&&ang<2.79))
  658.                                             rbit[PixIndex(l,b)].SetPixel(x,y);
  659.                                     }
  660.                                 }
  661.                             }
  662.                             break;
  663.                 default:    for (y=0;y<d;y++) {
  664.                                 for (x=0;x<d;x++) {
  665.                                     if (!pv[x+y*d].IsZero()) {
  666.                                         rbit[PixIndex(l,b)].SetPixel(x,y);
  667.                                     }
  668.                                 }
  669.                             }
  670.                             break;
  671.                 }
  672.             }
  673.         }
  674.  
  675.         printf( "\b\b\bdone\n" );
  676.     }
  677.  
  678.  
  679.  
  680. //
  681. // RingState-Felder anfordern und initialisieren
  682. // - zu jeder Pixmap existiert dabei in ein Eintrage mit einer
  683. //   Folgepixmap in Feldern zu jeder Himmelsrichtung.
  684. //
  685.     DBG4( UnixTrace, "RingStateData:>%7ld Bytes (for %dx%d=%d States)\n",
  686.                  4*vecs_all*sizeof(RingState), vecs_l, vecs_b, vecs_all );
  687.  
  688.     right    = new RingState[vecs_all];
  689.     left    = new RingState[vecs_all];
  690.     up        = new RingState[vecs_all];
  691.     down    = new RingState[vecs_all];
  692.  
  693. //
  694. // Stuffer anlegen und initialisieren
  695. //
  696. Stuffer    stuff;
  697.     for (i=0,l=vecs_all;l;l>>=1)    i++;        // Bits in vecs_all zaehlen
  698.     stuff.Init(i,sizeof(RingState));
  699.  
  700.     if (fp) {
  701.         printf( "reading %s\n", fname );
  702.  
  703. #ifndef LEFT_RIGHT_OPT
  704.         fread( right,1,stuff.SSize(vecs_all), fp );
  705.         stuff.Expand( right, vecs_all );
  706.         fread( left, 1,stuff.SSize(vecs_all), fp );
  707.         stuff.Expand( left, vecs_all );
  708. #endif
  709.         fread( up,   1,stuff.SSize(vecs_all), fp );
  710.         stuff.Expand( up, vecs_all );
  711.         fread( down, 1,stuff.SSize(vecs_all), fp );
  712.         stuff.Expand( down, vecs_all );
  713.     }
  714.     else {
  715. Real    b_ang = (double)mult*M_PI/vecs_b;    // Rotationswinkel pro Pixel
  716.  
  717.         printf( "state processing: 00%%" ); fflush(stdout);
  718.  
  719.         for (l=0;l<vecs_l;l++) {
  720.             printf( "\b\b\b%02d%%", (int)100*l/vecs_l ); fflush(stdout);
  721.  
  722.             for (int b=0;b<vecs_b;b++) {
  723.                 RingState    st = AngVec2St(l,b);                // aktueller Index
  724.                 RingState    nst;                                    // auszurechnender State
  725.                 Real    newl, newb;
  726.  
  727.                 Vec3    v( lToDeg(l), bToDeg(b) );
  728.  
  729.                 v.XTurnAngleRad(b_ang).GetPolarRad(&newl,&newb);
  730.                 nst = AngRad2St( newl, newb );
  731.                 if (st==nst)    DBG2( Loops, "Loop-Warning Up:    %03d/%03d\n",l,b );
  732.                 up[st] = nst;
  733.  
  734.  
  735.                 v.XTurnAngleRad(-b_ang).GetPolarRad(&newl,&newb);
  736.                 nst = AngRad2St( newl, newb );
  737.                 if (st==nst)    DBG2( Loops, "Loop-Warning Down:  %03d/%03d\n",l,b );
  738.                 down[st] = nst;
  739.  
  740. #ifndef LEFT_RIGHT_OPT
  741.                 v.ZTurnAngleRad(-b_ang).GetPolarRad(&newl,&newb);
  742.                 nst = AngRad2St( newl, newb );
  743.                 if (st==nst)    DBG2( Loops, "Loop-Warning Right: %03d/%03d\n",l,b );
  744.                 right[st] = nst;
  745.  
  746.                 v.ZTurnAngleRad(b_ang).GetPolarRad(&newl,&newb);
  747.                 nst = AngRad2St( newl, newb );
  748.                 if (st==nst)    DBG2( Loops, "Loop-Warning Left:  %03d/%03d\n",l,b );
  749.                 left[st] = nst;
  750. #endif
  751.             }
  752.         }
  753.  
  754.         printf( "\b\b\bdone\n" );
  755.  
  756.         DBG1( UnixTrace, "Time: %g secs.\n", GetCurrentTime()-start_time );
  757.     }
  758.     
  759. #ifdef LEFT_RIGHT_OPT
  760.     for (l=0;l<vecs_l;l++) {
  761.         for (int b=0;b<vecs_b;b++) {
  762.             RingState    st = AngVec2St(l,b);                // aktueller Index
  763.             right[st] = AngVec2StBnd((l+(vecs_l*(int)sym)-mult)%(vecs_l*(int)sym),b);
  764.             left[st]  = AngVec2StBnd((l+mult)%(vecs_l*(int)sym),b);
  765.         }
  766.     }
  767. #endif
  768.  
  769. #ifdef DEBUG
  770.     if (debug&ShowRings) {
  771.         //
  772.         // Eine spezielle Pixmap wird erzeugt, die eine Negation der Balldarstellung
  773.         // ist, um in dem Trace-Window einzelne Pixmap's herzuheben.
  774.         //
  775.         nbpix    = XCreatePixmap(dpy,bpix,d+o,d+o,1);
  776.         GC    gc = XCreateGC( dpy, nbpix, 0, 0l );
  777.         XSetFunction(dpy,gc,GXset);
  778.         XFillRectangle(dpy,nbpix,gc,0,0,d+o,d+o);            // alle Pixmap setzen
  779.         XSetFunction(dpy,gc,GXxor);
  780.         XCopyArea(dpy,bpix,nbpix,gc,0,0,d,d,o/2,o/2);    // Ball l÷schen
  781.         XFreeGC(dpy,gc);
  782.     }
  783. #endif
  784.  
  785.     if (fp) {
  786.         fclose(fp);
  787.         fp = 0;
  788.     }
  789.     else {
  790.         fp = fopen( fname, "w" );
  791.     }
  792. //
  793. // Bitmaps in Pixmaps wandeln und interne Strukturen freigeben
  794. //
  795.     rpix = new Pixmap[rpixs_all];
  796.     for (i=0;i<rpixs_all;i++) {
  797.         rpix[i] = rbit[i].Create();
  798.         if (fp) rbit[i].Write( fp );
  799.     }
  800.     delete [] rbit;
  801.     delete [] pv;
  802.  
  803.     if (fp) {
  804.         printf( "writing %s\n", fname );
  805.  
  806. #ifndef LEFT_RIGHT_OPT
  807.         stuff.Shrink( right, vecs_all );
  808.         fwrite( right,1,stuff.SSize(vecs_all), fp );
  809.         stuff.Expand( right, vecs_all );
  810.         stuff.Shrink( left, vecs_all );
  811.         fwrite( left, 1,stuff.SSize(vecs_all), fp );
  812.         stuff.Expand( left, vecs_all );
  813. #endif
  814.         stuff.Shrink( up, vecs_all );
  815.         fwrite( up,   1,stuff.SSize(vecs_all), fp );
  816.         stuff.Expand( up, vecs_all );
  817.         stuff.Shrink( down, vecs_all );
  818.         fwrite( down, 1,stuff.SSize(vecs_all), fp );
  819.         stuff.Expand( down, vecs_all );
  820.         fclose(fp);
  821.     }
  822. }
  823.  
  824.  
  825.  
  826. void HalfBallMover::CreateRingWindow() {
  827.     tw=CreateWindow( "Ringverteilung", rpixs_l*(d+o)+1 , rpixs_b*(d+o)+1 );
  828.     for (int l=0;l<rpixs_l;l++) {
  829.         for (int b=0;b<rpixs_b;b++) {
  830.             XCopyPlane(dpy,bpix,tw,gc_ballwhite,0,0,d,d,o/2+l*(d+o),o/2+b*(d+o),1);
  831.             XCopyPlane(dpy,lpix[(l*lpixs_x/rpixs_l)+(b*lpixs_y/rpixs_b)*lpixs_x],tw,gc_lay2,0,0,d,d,o/2+l*(d+o),o/2+b*(d+o),1);
  832.             XCopyPlane(dpy,rpix[PixIndex(rpixs_l-1-l,b)],tw,gc_ball[7],0,0,d,d,o/2+l*(d+o),o/2+b*(d+o),1);
  833.         }
  834.     }
  835. #ifdef DEBUG
  836.     if (debug&xwd) {
  837.         char command[200];
  838.         XSync(dpy,0);
  839.         sprintf( command, "/usr/bin/X11/xwd -id %ld -frame > XWD/rings", tw );
  840.         system(command);
  841.     }
  842. #endif
  843. }
  844.  
  845.  
  846. #define _INFO
  847.  
  848. void HalfBallMover::CreateTurnWindow() {
  849. Window    win;
  850.  
  851.     win=CreateWindow( "Senkrecht-Rotation", rpixs_b*(d+o)+1,2*rpixs_b*(d+o)+1 );
  852.     for (int b=0;b<rpixs_b;b++) {
  853. #ifdef INFO
  854.         printf( "Row %d: angle: %f\n", b, (double)bToDeg(b*mult+mult2) );
  855. #endif
  856.         RingState    st = AngPix2St(0,b);
  857.         for (int y=0;y<2*rpixs_b;y++) {
  858. #ifdef INFO
  859.         int lp,bp;
  860.         int lv,bv;
  861.     //
  862.     // Ausgabe der Tabellenerte
  863.     //
  864.         St2AngVec(st,&lv,&bv);
  865.         St2AngPix(st,&lp,&bp);
  866.         printf( "  Line %2d: Vec2: %03d/%03d, Pixmap: %02d/%02d",
  867.             y, lv, bv, lp, bp );
  868.  
  869.     //
  870.     // Berechnung der direkten Werte zum Vergleich
  871.     //
  872.         Real    b_ang=(double)mult*M_PI/vecs_b;   // Rotationswinkel pro Pixel
  873.         Vec3    v( lToDeg(mult2), bToDeg(b*mult+mult2) );
  874.         Real    newl, newb;
  875.         v.XTurnAngleRad((y*b_ang)).GetPolarRad(&newl,&newb);
  876.         RingState nst = AngRad2St( newl, newb );
  877.     // Ausgabe
  878.         St2AngVec(nst,&lv,&bv);
  879.         St2AngPix(nst,&lp,&bp);
  880.         printf( " <=> Vec2: %03d/%03d, Pixmap: %02d/%02d\n",
  881.             lv, bv, lp, bp );
  882.  
  883.         if (((b^y)&1)) {
  884.             XCopyPlane(dpy,bpix,win,gc_ballwhite,0,0,d,d,o/2+b*(d+o),o/2+y*(d+o),1);
  885.             XCopyPlane(dpy,lpix[(b*lpixs_x/rpixs_b)+(y/2*lpixs_y/rpixs_b)*lpixs_x],win,gc_lay2,0,0,d,d,o/2+b*(d+o),o/2+y*(d+o),1);
  886.             XCopyPlane(dpy,rpix[PixIndex(nst)],win,gc_ball[7],0,0,d,d,o/2+b*(d+o),o/2+y*(d+o),1);
  887.         }
  888.         else
  889. #endif
  890.         {
  891.             XCopyPlane(dpy,bpix,win,gc_ballwhite,0,0,d,d,o/2+b*(d+o),o/2+y*(d+o),1);
  892.             XCopyPlane(dpy,lpix[(b*lpixs_x/rpixs_b)+(y/2*lpixs_y/rpixs_b)*lpixs_x],win,gc_lay2,0,0,d,d,o/2+b*(d+o),o/2+y*(d+o),1);
  893.             XCopyPlane(dpy,rpix[PixIndex(st)],win,gc_ball[8],0,0,d,d,o/2+b*(d+o),o/2+y*(d+o),1);
  894.         }
  895.             st = Turn(st,0,1);
  896.         }
  897.     }
  898. #ifdef DEBUG
  899.     if (debug&xwd) {
  900.         char command[200];
  901.         XSync(dpy,0);
  902.         sprintf( command, "/usr/bin/X11/xwd -id %ld -frame > XWD/turns", win );
  903.         system(command);
  904.     }
  905. #endif
  906. }
  907.  
  908.  
  909.  
  910. #if (1)
  911.  
  912. #define    LINE(DY,YDEC,YADDOP,YTAB,DX,XLESS,XTAB) \
  913.     int    dy_c = DY; \
  914.     int    c    = 0; \
  915.     while(DY) { \
  916.         st = YTAB [st]; \
  917.         DY YDEC; \
  918.         c -= DX;    \
  919.         if (c XLESS 0) {    \
  920.             c YADDOP dy_c;    \
  921.             st = XTAB [st];    \
  922.         };    \
  923.     }
  924.  
  925.  
  926. RingState HalfBallMover::Turn( RingState st, int dx, int dy ) {
  927.  
  928.     if (dx>0) {
  929.         if (dy>0) {
  930.             if (dy>dx)    { LINE(dy,--,+=,up,   dx,<,right);    }
  931.             else            { LINE(dx,--,+=,right,dy,<,up);        }
  932.         }
  933.         else {                // dy negativ => alle DY-Parameter umkehren
  934.             if (-dy>dx)    { LINE(dy,++,-=,down, dx,<,right);    }
  935.             else            { LINE(dx,--,+=,right,dy,>,down);    }
  936.         }
  937.     }
  938.     else {                // dx negativ => alle DX-Parameter umkehren
  939.         if (dy>0) {
  940.             if (dy>-dx)    { LINE(dy,--,+=,up,   dx,>,left);    }
  941.             else            { LINE(dx,++,-=,left ,dy,<,up);        }
  942.         }
  943.         else {                // dy negativ => alle DY-Parameter umkehren
  944.             if (-dy>-dx){ LINE(dy,++,-=,down, dx,>,left);    }
  945.             else            { LINE(dx,++,-=,left ,dy,>,down);    }
  946.         }
  947.     }
  948.  
  949.     return st;
  950. }
  951.  
  952. #else
  953. RingState HalfBallMover::Turn( RingState st, int dx, int dy ) {
  954.     while( dx && dy ) {
  955.         if (dx>0)                {    dx--; st = right[st];    }
  956.         else if (dx<0)            {    dx++; st = left[st]; }
  957.         if (dy>0)                {    dy--;    st = up[st];    }
  958.         else if (dy<0)            {    dy++;    st = down[st];    }
  959.     }
  960.     if (dx>0)                { while(dx--)        st = right[st]; }
  961.     else if (dx<0)            { while(dx++)        st = left[st]; }
  962.     if (dy>0)                { while(dy--)        st = up[st]; }
  963.     else if (dy<0)            { while(dy++)        st = down[st]; }
  964.     return st;
  965. }
  966. #endif
  967.  
  968.  
  969. void HalfBallMover::RollBallAt( int x, int y, RingState st, int col_x )
  970. {
  971. #ifndef NODRAW
  972.     XFillRectangle(dpy,help,gc_bclear,0,0,d,d);
  973.     XCopyPlane(dpy,bpix,help,gc_ballwhite,0,0,d,d,0,0,1);
  974.     XCopyPlane(dpy,GetShadowMap(x,y),help,gc_lay2,0,0,d,d,0,0,1);
  975.     XCopyPlane(dpy,rpix[PixIndex(st)],help,gc_ball[col_x],0,0,d,d,0,0,1);
  976.     XCopyArea(dpy,help,win,gc_bxor,0,0,d,d,x-r, y-r );
  977.  
  978. #ifdef DEBUG
  979.     if ((tw)&&(debug&ShowRings)) {
  980.         int    l,b;
  981.         St2AngPix(st,&l,&b);
  982.         XCopyPlane(dpy,nbpix,tw,gc_ballwhite,  0,0,d+o,d+o,(rpixs_l-1-l)*(d+o),b*(d+o),1);
  983.         XCopyPlane(dpy,nbpix,tw,gc_ball[col_x],0,0,d+o,d+o,(rpixs_l-1-l)*(d+o),b*(d+o),1);
  984.     }
  985. #endif
  986. #endif
  987. }
  988.  
  989.  
  990. void HalfBallMover::RollBallOnScreen( int oldx, int oldy, RingState ost,
  991.                 int newx, int newy, RingState *nst, int col_x ) {
  992.  
  993. int    dx = newx-oldx;
  994. int    dy = newy-oldy;
  995.  
  996.         *nst = Turn( ost, dx, dy );
  997.  
  998. int absx = (dx>0)?dx:-dx;
  999. int absy = (dy>0)?dy:-dy;
  1000.  
  1001. #ifndef NODRAW
  1002.     if ( (absx<d_help-d) && (absy<d_help-d) ) {
  1003.         int    width = d+absx;        // tatsΣchlicher Ausschnittgr÷▀e der Pixmap
  1004.         int    height= d+absy;
  1005.         int    ox = (dx>0)?0:absx;    // relativer Abstand alte Position
  1006.         int    oy = (dy>0)?0:absy;
  1007.         int    nx = (dx>0)?absx:0;    // relativer Abstand neue Position
  1008.         int    ny = (dy>0)?absy:0;
  1009.  
  1010.         XFillRectangle(dpy,help,gc_bclear,0,0,width,height);
  1011.  
  1012.         XCopyPlane(dpy,bpix,help,gc_ballwhite,0,0,d,d,ox,oy,1);
  1013.         XCopyPlane(dpy,GetShadowMap(oldx,oldy),help,gc_lay2,0,0,d,d,ox,oy,1);
  1014.         XCopyPlane(dpy,rpix[PixIndex(ost)],help,gc_ball[col_x],0,0,d,d,ox,oy,1);
  1015.  
  1016.         XCopyPlane(dpy,bpix,help,gc_ballwhite,0,0,d,d,nx,ny,1);
  1017.         XCopyPlane(dpy,GetShadowMap(newx,newy),help,gc_lay2,0,0,d,d,nx,ny,1);
  1018.         XCopyPlane(dpy,rpix[PixIndex(*nst)],help,gc_ball[col_x],0,0,d,d,nx,ny,1);
  1019.  
  1020.         XCopyArea(dpy,help,win,gc_bxor,0,0,width,height,oldx-ox-r, oldy-oy-r );
  1021.  
  1022. #ifdef DEBUG
  1023.         if ((tw)&&(debug&ShowRings)) {
  1024.             int    l,b;
  1025.             St2AngPix(ost,&l,&b);
  1026.             XCopyPlane(dpy,nbpix,tw,gc_ballwhite,  0,0,d+o,d+o,l*(d+o),b*(d+o),1);
  1027.             XCopyPlane(dpy,nbpix,tw,gc_ball[col_x],0,0,d+o,d+o,l*(d+o),b*(d+o),1);
  1028.             St2AngPix(*nst,&l,&b);
  1029.             XCopyPlane(dpy,nbpix,tw,gc_ballwhite,  0,0,d+o,d+o,l*(d+o),b*(d+o),1);
  1030.             XCopyPlane(dpy,nbpix,tw,gc_ball[col_x],0,0,d+o,d+o,l*(d+o),b*(d+o),1);
  1031.         }
  1032. #endif
  1033.  
  1034.     }
  1035.     else {
  1036.         RollBallAt(oldx,oldy,ost,col_x);
  1037.         RollBallAt(newx,newy,*nst,col_x);
  1038.     }
  1039. #endif
  1040.  
  1041. #ifdef STATISTICS
  1042.     moves++;
  1043. #endif
  1044. }
  1045.  
  1046.